제네릭 프로그래밍의 한계<limits> 헤더는 컴퓨터 하드웨어에 따라 다른 타입에 대한 중요한 정보를 제공한다.
<limits> 헤더 내에서 numeric_limits 클래스 템플릿은 내장 타입별 정보를 전달한다.
template <class T>class numeric_limits;
numeric_limits 클래스는 템플릿 특수화로 구현되어 있다.
명시된 타입의 최댓값이나 최솟값 등을 질의할 때 사용
#include <iostream>
#include <limits>
using namespace std;
template<typename T>
inline void test(const T& x){
cout<<"x= "<<x<<"(";
int oldp=cout.precision(numeric_limits<T>::digits10+1);
cout<<x<<")"<<endl;
cout.precision(oldp);
}
int main(void){
test(1.f/3.f);
test(1./3.0);
test(1.l/3.0l);
}
x= 0.333333(0.3333333)
x= 0.333333(0.3333333333333333)
x= 0.333333(0.3333333333333333)
digits10(member)number of decimal digits that can be represented without change
digits(member)
number of radix digits that can be represented without change
numer_limits에 컴파일 타임 상수로 주어진다.
template <typename Container>
typename Container::value_type inline minimum(const Container& c){
using vt=typename Container::value_type;
vt min_value=numeric_limits<vt>::max();
for(const vt& x: c){
if(x<min_value) min_value=x;
}
return min_value;
}
min(), max() 메서드는 내부에 static으로 선언되어 있어 인스턴스를 생성하지 않고도 호출할 수 있다.
고정소수점 계산의 종류 기준은 타입에 따라 달라진다.
template <typename T>
T square_root(const T& x){
const T my_eps=T{2}*x*numeric_limits<T>::epsilon();
T r=x;
while(std::abs((r*r)-x)>my_eps) r=(r+x/r)/T{2};
return r;
}
타입 특성
g++ 4.9 및 clang 3.4는 타입 특성 지원하지 않음
g++ 5.1 및 clang 3.5에서 부터 타입 특성 기능 구현
<Boost> 라이브러리에서 수년간 많이 사용된 타입 특성(type trait)은 C++11에서 표준화되어
<type_traits> 헤더에서 표준으로 제공된다.
is_pod는 C와의 호환성을 위해 사용된다.
POD(Plain Old Data) 타입인지 여부를 반환
POD 타입은 C에서도 사용가능한, 내장타입(intrinsic_type)과 “단순한" 클래스(구조체) 타입을 의미
C와 C++에서 사용되는 클래스의 경우, C 호환 방식으로 한번만 정의해서 사용하는 것이 좋다.(클래스가 struct이어야 하고, 메서드가 없거나 조건부 컴파일 되어야 함)
virtual 함수 및 static 데이터 멤버가 포함되면 안된다.
클래스의 메모리 레이아웃이 C와 호환되어야 하고, 디폴트 생성자와 복사 생성자가 자명(trivial)해야 함
default로 선언 혹은 컴파일러가 디폴트 방식으로 생성
struct simple_point{
#ifdef __cplusplus
simple_point(double x, double y): x(x), y(y){}
simple_point()=default;
simple_point(initializer_list<double> il){
auto it=begin(il);
x=*it;
y=*next;
}
#endif
double x, y;
};
위의 코드가 C 컴파일러(ex gcc)로 컴파일될 경우, struct 구조(멤버변수)만 선언된다.
__cplusplus 매크로는 모든 C++ 컴파일러에서 미리 정의된다.
(컴파일러가 지원하는 표준을 표시)
int main(void){
cout<<"simple_point is pod = "<<boolalpha<<is_pod<simple_point>::value<<endl;
simple_point p1={3.0, 7.0};
return 0;
}
NVIDIA의 CUDA 라이브러리도 이와 같은 스타일로 몇 개의 클래스를 구현하고 있다.
POD는 메모리에 연속적으로 저장되며 복사 생성자를 호출하지 않고 원시 데이터로 복사할 수 있다.
(memcpy나 memmove 함수를 이용)
#include <string.h>
void* memcpy(void* destination, const void* source, size_t num);
is_trivial_copyable를 이용해서 저수준 복사 기능을 실재로 호출할 수 있는지 확인할 수 있다
simple_point p1{3.0, 7.1}, p2;
static_assert(std::is_trivially_copyable<simple_point>::value, "simple_point is not as simple as you think and cannot be memcpyd!");
std::memcpy(&p2, &p1, sizeof(p1));
C++14부터 아래 템플릿 별칭을 지원한다.
위는 내부적으로 아래 타입의 약어이다.
typename conditional<B, T, F>::type;
enable_if_t 또한 enable_if 타입의 약어이다.